package com.llyb.tingshu.album.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.llyb.tingshu.album.mapper.AlbumInfoMapper;
import com.llyb.tingshu.album.mapper.AlbumStatMapper;
import com.llyb.tingshu.album.mapper.TrackInfoMapper;
import com.llyb.tingshu.album.mapper.TrackStatMapper;
import com.llyb.tingshu.album.service.AlbumInfoService;
import com.llyb.tingshu.album.service.TrackInfoService;
import com.llyb.tingshu.album.service.VodService;
import com.llyb.tingshu.common.constant.SystemConstant;
import com.llyb.tingshu.common.execption.GuiguException;
import com.llyb.tingshu.common.rabbit.constant.MqConst;
import com.llyb.tingshu.common.rabbit.service.RabbitService;
import com.llyb.tingshu.common.result.Result;
import com.llyb.tingshu.common.result.ResultCodeEnum;
import com.llyb.tingshu.model.album.AlbumInfo;
import com.llyb.tingshu.model.album.AlbumStat;
import com.llyb.tingshu.model.album.TrackInfo;
import com.llyb.tingshu.model.album.TrackStat;
import com.llyb.tingshu.query.album.TrackInfoQuery;
import com.llyb.tingshu.user.client.UserInfoFeignClient;
import com.llyb.tingshu.vo.album.*;
import com.llyb.tingshu.vo.user.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;

	@Autowired
	private AlbumInfoService albumInfoService;

	@Autowired
	private VodService vodService;

	@Autowired
	private TrackStatMapper trackStatMapper;

	@Autowired
	private UserInfoFeignClient userInfoFeignClient;

	@Autowired
	private AlbumStatMapper albumStatMapper;

	@Autowired
	private RabbitService rabbitService;

	@Autowired
	private AlbumInfoMapper albumInfoMapper;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveTrackInfo(TrackInfoVo trackInfoVo,Long userId) {
		TrackInfo trackInfo = new TrackInfo();

		BeanUtils.copyProperties(trackInfoVo,trackInfo);

		trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
		trackInfo.setUserId(userId);
		AlbumInfo albumInfo1 = albumInfoService.getOne(new LambdaQueryWrapper<AlbumInfo>().
				eq(AlbumInfo::getId, trackInfoVo.getAlbumId()));
		trackInfo.setOrderNum(albumInfo1.getIncludeTrackCount()+1);

		TrackMediaInfoVo trackMediaInfo =  vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId());
		trackInfo.setMediaSize(trackMediaInfo.getSize());
		trackInfo.setMediaUrl(trackMediaInfo.getMediaUrl());
		trackInfo.setMediaDuration(trackMediaInfo.getDuration());
		trackInfo.setMediaType(trackMediaInfo.getType());


		this.save(trackInfo);

		// 更新专辑信息表的数量

		albumInfoService.update(new LambdaUpdateWrapper<AlbumInfo>().
				eq(AlbumInfo::getId, trackInfoVo.getAlbumId()).
				set(AlbumInfo::getIncludeTrackCount,albumInfo1.getIncludeTrackCount()+1));


		// 初始化统计数据
		this.saveTrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_PLAY);
		this.saveTrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_COLLECT);
		this.saveTrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_PRAISE);
		this.saveTrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_COMMENT);
	}

	@Override
	public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> page, TrackInfoQuery trackInfoQuery) {
		return trackInfoMapper.selectUserTrackPage(page,trackInfoQuery);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean removeTrackInfo(Long trackId) {
		// 删除trackInfo , trackStat, 云点播

		TrackInfo trackInfo = trackInfoMapper.selectOne(new LambdaQueryWrapper<TrackInfo>().
				eq(TrackInfo::getId, trackId));
		this.removeById(trackId);
		// 设置比当前声音的排序大的声音的排序减1
		trackInfoMapper.updateOrderByOrderNum(trackInfo.getAlbumId(),trackInfo.getOrderNum());


		// 更新专辑信息表数量
		AlbumInfo albumInfo = albumInfoService.getOne(new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getId, trackInfo.getAlbumId()));
		albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount()-1);
		albumInfoService.updateById(albumInfo);

		// 删除统计数据
		trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().
				eq(TrackStat::getTrackId,trackId));

		// 删除云点播文件
		vodService.deleteMedia(trackInfo.getMediaFileId());

		return true;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateStat(TrackStatMqVo trackStatMqVo) {

		// 更新专辑播放量

		Long albumId = trackStatMqVo.getAlbumId();
		if (null != albumId) {
			AlbumStat albumStat = albumStatMapper.selectOne(new LambdaQueryWrapper<AlbumStat>().
					eq(AlbumStat::getAlbumId, albumId).eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_PLAY));

			if (null != albumStat) {
				albumStat.setStatNum(albumStat.getStatNum()+trackStatMqVo.getCount());
				albumStatMapper.updateById(albumStat);
			}
		}

		// 更新声音播放量
		Long trackId = trackStatMqVo.getTrackId();
		if (null != trackId) {
			TrackStat trackStat = trackStatMapper.selectOne(new LambdaQueryWrapper<TrackStat>().
					eq(TrackStat::getTrackId, trackId).eq(TrackStat::getStatType, trackStatMqVo.getStatType()));
			if (null != trackStat) {
				trackStat.setStatNum(trackStat.getStatNum()+trackStatMqVo.getCount());
				trackStatMapper.updateById(trackStat);
			}
		}

		// 同步修改es中数据
		rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumId);

	}

	@Override
	public IPage<AlbumTrackListVo> findAlbumTrackPage(IPage<AlbumTrackListVo> iPage, Long albumId, Long userId) {

		/**
		 * 1. 查询专辑下所有的声音
		 *
		 * 	提出来：专辑是免费专辑，全部显示
		 *
		 * 2. 判断用户有没有登录
		 * 		2.1 没登陆
		 * 		 	非免费专辑，只显示专辑中试听声音，付费的，上锁
		 * 		2.2 已登录
		 * 			2.2.1判断专辑的付费类型
		 *   			2.2.1.1 专辑是vip免费，判断用户是否购买
		 *   			2.2.1.2 专辑是vip付费，判断用户是否购买
		 */

		AlbumInfo albumInfo = albumInfoService.getById(albumId);

		IPage<AlbumTrackListVo> albumTrackListVoIPage = trackInfoMapper.selectPageByAlbumId(iPage,albumId);

		// 免费专辑
		if (SystemConstant.ALBUM_PAY_TYPE_FREE.equalsIgnoreCase(albumInfo.getPayType())) {
			albumTrackListVoIPage.getRecords().stream().forEach(albumTrackListVo -> {
				albumTrackListVo.setIsShowPaidMark(false);
			});
			return albumTrackListVoIPage;
		}

		// 未登录只能看试听集数
		Integer tracksForFree = albumInfo.getTracksForFree();
		if (null == userId && tracksForFree!=null && tracksForFree>0) {
			// 显示免费试听集数
			albumTrackListVoIPage.getRecords().stream()
					.filter(albumTrackListVo -> albumTrackListVo.getOrderNum()>tracksForFree)
					.forEach(albumTrackListVo -> {
						albumTrackListVo.setIsShowPaidMark(true);
					});
		}

		// 已登录
		if (null != userId) {

			boolean isPaid = false;
			// 2.2.1.1 专辑是vip免费，判断用户是否购买
			if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equalsIgnoreCase(albumInfo.getPayType())){
				// 获取用户是否是vip
				Result<UserInfoVo> userInfoR = userInfoFeignClient.getUserInfo(userId);
				Assert.notNull(userInfoR, "获取用户信息失败");
				UserInfoVo userInfoVo = userInfoR.getData();
				Assert.notNull(userInfoVo, "获取用户信息失败");

				if (userInfoVo.getIsVip()==0) {
					isPaid = true;
				}
				if (userInfoVo.getIsVip()==1 && userInfoVo.getVipExpireTime().before(new Date())){
					isPaid = true;
				}
			}else if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equalsIgnoreCase(albumInfo.getPayType())){
				isPaid = true;
			}

			if (isPaid) {
				// 除了免费声音 的 trackid list
				List<Long> unconfirmedTrackList = albumTrackListVoIPage.getRecords().stream()
						.filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
						.map(albumTrackListVo -> albumTrackListVo.getTrackId())
						.collect(Collectors.toList());

				if (!CollectionUtils.isEmpty(unconfirmedTrackList)) {
					// 远程调用，传入idlist, 返回结果map<Long,Integer>
					Result<Map<Long, Integer>> mapResult = userInfoFeignClient.userIsPaidTrack(albumId, unconfirmedTrackList);
					Assert.notNull(mapResult, "远程调用获取用户购买的声音失败");
					Map<Long, Integer> isPaiedTrackMap = mapResult.getData();
					Assert.notNull(isPaiedTrackMap, "获取的用户购买的声音为空");
					albumTrackListVoIPage.getRecords().stream()
							.filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
							.forEach(albumTrackListVo -> {
								albumTrackListVo.setIsShowPaidMark(isPaiedTrackMap.get(albumTrackListVo.getTrackId())==0);
							});
				}
			}

		}

		return albumTrackListVoIPage;
	}

	@Override
	public boolean updateTrackInfo(TrackInfo trackInfo) {

		TrackInfo originalTrackInfo = this.getById(trackInfo.getId());
		String originalTrackInfoMediaFileId = originalTrackInfo.getMediaFileId();

		if (!originalTrackInfoMediaFileId.equalsIgnoreCase(trackInfo.getMediaFileId())) {
			vodService.deleteMedia(originalTrackInfo.getMediaFileId());
			TrackMediaInfoVo trackMediaInfo = vodService.getTrackMediaInfo(trackInfo.getMediaFileId());
			if (null == trackMediaInfo) {
				throw new GuiguException(ResultCodeEnum.VOD_FILE_ID_ERROR);
			}
			trackInfo.setMediaSize(trackMediaInfo.getSize());
			trackInfo.setMediaUrl(trackMediaInfo.getMediaUrl());
			trackInfo.setMediaDuration(trackMediaInfo.getDuration());
			trackInfo.setMediaType(trackMediaInfo.getType());
		}

		return this.updateById(trackInfo);
	}

	@Override
	public List<Map<String, Object>> findUserTrackPaidList(Long trackId, Long userId) {
		List<Map<String, Object>> list = new ArrayList<>();

		TrackInfo trackInfoById = this.getById(trackId);

		// 远程调用，获取用户已经购买的声音集合
		Result<List<Long>> userPaidTrackListR = userInfoFeignClient.findUserPaidTrackList(trackInfoById.getAlbumId());
		Assert.notNull(userPaidTrackListR, "远程调用获取用户购买的声音失败");
		List<Long> userPaidTrackList = userPaidTrackListR.getData();

		// 根据 trackid 获取所有list，
		LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
		if (!CollectionUtils.isEmpty(userPaidTrackList)) {
			wrapper.notIn(TrackInfo::getId, userPaidTrackList);
		}
		wrapper.eq(TrackInfo::getAlbumId, trackInfoById.getAlbumId());
		wrapper.ge(TrackInfo::getOrderNum,trackInfoById.getOrderNum());
		List<TrackInfo> trackInfoList = trackInfoMapper.selectList(wrapper);

		// 赋值list
		// 可以从专辑中获取专辑单价
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoById.getAlbumId());

		// 判断 trackInfoList 的大小，每十个赋值一个map，放入list
		if (trackInfoList.size()>0){
			Map<String, Object> map = new HashMap<>();
			map.put("name","本集");
			map.put("price",albumInfo.getPrice());
			map.put("trackCount",1);
			list.add(map);

			// 每十集分配一个map
			if (trackInfoList.size() == 1){
				return list;
			}
			int totalTrackCount = trackInfoList.size() > 50 ? 50 : trackInfoList.size();
			for (int i = 1; i <= totalTrackCount; i+=10){
				int count = Math.min(i + 9, totalTrackCount);
				Map<String, Object> segmentMap = new HashMap<>();
				segmentMap.put("name","后"+ count +"集，包含本集");
				segmentMap.put("price",albumInfo.getPrice().multiply(BigDecimal.valueOf(count)));
				segmentMap.put("trackCount",count);
				list.add(segmentMap);
			}

		}

		return list;
	}

	public void saveTrackStat(Long id, String trackStatPraise) {
		TrackStat trackStat = new TrackStat();
		trackStat.setTrackId(id);
		trackStat.setStatType(trackStatPraise);
		trackStat.setStatNum(new Random().nextInt(10000));
		trackStatMapper.insert(trackStat);
	}

	/**
	 * 批量获取下单付费声音列表
	 *
	 * @param trackId
	 * @param trackCount
	 * @return List<TrackInfo>
	 */
	@Override
	public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer trackCount) {

		TrackInfo trackInfoById = this.getById(trackId);
		// 远程调用用户已经购买的声音
		Result<List<Long>> userPaidTrackList = userInfoFeignClient.findUserPaidTrackList(trackInfoById.getAlbumId());
		Assert.notNull(userPaidTrackList, "远程调用获取用户购买的声音失败");
		List<Long> paidTrackList = userPaidTrackList.getData();
		// 用户已购买的声音可以为空，此时返回所有声音
		LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(TrackInfo::getAlbumId, trackInfoById.getAlbumId())
				.ge(TrackInfo::getOrderNum, trackInfoById.getOrderNum());
		if (!CollectionUtils.isEmpty(paidTrackList)) {
			wrapper.notIn(TrackInfo::getId, paidTrackList);
		}
		wrapper.last(" limit " + trackCount);
		List<TrackInfo> trackInfos = trackInfoMapper.selectList(wrapper);

		return trackInfos;
	}
}
